/*=======================================================
컴포넌트명  : 한글 자동 완성 컴포넌트 
만든이 	 : martin0729@nate.com
만든날짜  	 : 2008.07.09
기타 사항    : Flex3 환겨에서 개발 하였습니다.
		    유용하게 사용 하세요. 
		    기능 추가 사항요청은 거절 합니다.  	   		  	
=========================================================*/
package Comp
{
	import flash.events.Event;
	import flash.events.FocusEvent;
	import flash.events.KeyboardEvent;
	import flash.events.MouseEvent;
	import flash.geom.Point;
	
	import mx.collections.*;
	import mx.controls.*;
	import mx.core.ClassFactory;
	import mx.events.ListEvent;
	import mx.managers.PopUpManager;
	import mx.utils.ObjectUtil;
	
	[Event(name="itemClick", type="mx.events.ListEvent")]
			
	[Bindable]
	public class HangulAutoTextInput extends TextInput{
		
	/*************************************************************************************
	 * Define
	 * *********************************************************************************/
		public var hac:HangulAutoComplete;
		private var keyStr:String;
		private var listFocuceFg:Boolean;
		private var dropDownOpenFg:Boolean;
		private var originalDataList:Object; // 원본
		private var copyDataProvider:ArrayCollection; 					
		
		
	/*************************************************************************************
	 * Set / Get Property..
	 * *********************************************************************************/

		//-----------------------------------------------//
		//	dropDownList		
		//-----------------------------------------------//
		
		private var _dropDownList:List;		

				
		public function get dropDownList():List{
	        return _dropDownList;
	    }

        
		//-----------------------------------------------//
		//	dropDownEnable		
		//-----------------------------------------------//
	
		private var _dropDownEnabled:Boolean = true;		
		[Inspectable(category="General", enumeration="true,false", defaultValue="true")]	
		public function set dropDownEnabled(value:Boolean):void{
			_dropDownEnabled = value;
		}
						
		public function get dropDownEnabled():Boolean{
	        return _dropDownEnabled;
	    }
	    	    	    										
		//-----------------------------------------------//
		// dropDownWidth
		//-----------------------------------------------//
		private var _dropDownWidth:Number;

		public function set dropDownWidth(value:Number):void{
			_dropDownWidth 		= value;
			dropDownList.width 	= _dropDownWidth;
		}

		public function get dropDownWidth():Number{
			return dropDownList.width;
		}
		
		//-----------------------------------------------//
		// dropDownAlign
		//-----------------------------------------------//				
		private var _dropDownAlign:String;

		[Inspectable(category="General", enumeration="left,right,center", defaultValue="left")]	
		public function set dropDownAlign(value:String):void{
			_dropDownAlign = value;
		}

		public function get dropDownAlign():String{
			return _dropDownAlign;
		}

		//-----------------------------------------------//
		// dataProvider
		//-----------------------------------------------//
		
	    public function set dataProvider(value:Object):void{
	    	var tempArc:ArrayCollection;
	    	var dataCount:int;
	    	if(value){
	    		
	    		originalDataList = mx.utils.ObjectUtil.copy(value); //원본 	 
	    		
	    		dropDownList.dataProvider = value;	    		
	    		if(dropDownList.dataProvider is XMLListCollection){
	    			tempArc = new ArrayCollection();
	    			dataCount = dropDownList.dataProvider.length;
	    			// 
	    			for(var i:int = 0 ; i < dataCount ; i++){
	    				tempArc.addItem(dropDownList.dataProvider[i]);
	    			}//for i
	    			dropDownList.dataProvider = tempArc;
	    		}
	    		
	    		copyDataProvider = mx.utils.ObjectUtil.copy(dropDownList.dataProvider) as ArrayCollection;	    		
	    			    		
	    	}else{
	    		originalDataList = null;
	    		copyDataProvider = null;
	    		dropDownList.dataProvider = null;
	    	}
	    		    	
	    }
	    	    		 
	    public function get dataProvider():Object{
	        return originalDataList;
	    }
	
		//-----------------------------------------------//
		// selectedIndex
		//-----------------------------------------------//
		private var _selectedIdx:int = -1;
		public function get selectedIndex():int{			
			return _selectedIdx;
		}		    		


		//-----------------------------------------------//
		// selectedItem
		//-----------------------------------------------//
		private var _selectedItem:Object;
		public function get selectedItem():Object{			
			return _selectedItem;		
		}		 
			    
	    //-----------------------------------------------//
	    // labelField
	    //-----------------------------------------------//	    
	    		
		public function set labelField(value:String):void{
			value = mx.utils.StringUtil.trim(value);
			if(value != ""){
				dropDownList.labelField = value;	
			}
			
		}

		public function get labelField():String{
			return dropDownList.labelField;
		}

		//-----------------------------------------------//
		// rowCount
		//-----------------------------------------------//
		public function set rowCount(value:int):void{
			dropDownList.rowCount = value;
		}

		public function get rowCount():int{
			return dropDownList.rowCount;
		}

 						
	/*************************************************************************************
	 * configration
	 * *********************************************************************************/	

		public function HangulAutoTextInput(){
			super();
			hac = new HangulAutoComplete();
			dropDownOpenFg 	= false;
			listFocuceFg	= false;
			keyStr 			= "";
			
			_dropDownList 		= new List();
			_dropDownList.id 	= "dropDownList"; 			
			_dropDownWidth 		= 200;
			_dropDownWidth 		=600;
			_dropDownAlign 		= "left";

			_dropDownList.itemRenderer = new ClassFactory(ComboBoxItemRenderer);
					
			addEventListener(FocusEvent.FOCUS_IN, TextInput_onFocusIn);
			addEventListener(FocusEvent.FOCUS_OUT, TextInput_onFocusOut);
		}

		override protected function createChildren():void{
			super.createChildren();
			eventListenerSet();
		}	
				
		protected function eventListenerSet():void{
												
 			dropDownList.addEventListener(MouseEvent.ROLL_OVER,mouseRollOverHandler,false,0,true);
			dropDownList.addEventListener(MouseEvent.ROLL_OUT,mouseRollOutHandler,false,0,true); 
					
			dropDownList.addEventListener(ListEvent.ITEM_CLICK,listItemClick,false,0,true);
			
			addEventListener(FocusEvent.FOCUS_IN, TextInput_onFocusIn,false,0,true);
			addEventListener(FocusEvent.FOCUS_OUT, TextInput_onFocusOut,false,0,true);
		}

        private function TextInput_onFocusIn(e:Event): void {
            this.textField.alwaysShowSelection = true;
        } 
        private function TextInput_onFocusOut(e:Event): void {
            this.textField.alwaysShowSelection = false;
        }		
	/*************************************************************************************
	 * eventHandler  
	 * *********************************************************************************/	

		
		
		override protected function keyUpHandler(event:KeyboardEvent):void{
			keyStr = textField.text;
			
			// 엔터클릭시 리턴 
			if(event.keyCode == 13) {
				return;
			}
			
			// esc키를 눌렀거나 아무것도 입력된 값이 없을경우 ... 드롭다운 리스트를 닫고 리턴 시킴 .
			if(event.keyCode == 27 || keyStr == "") {
				closeDropDown();	
				//return;
			} 
			
			// 마우스 커서가 아래로 향하면 드롭다운 리스트로 포커스를 이동시킨다 .
			if(event.keyCode == 40) { 
				dropDownList.focusEnabled = true;				
				dropDownList.setFocus();
			}
			
			// 키 업 되었을때 실제 search 시작 
			openDropDown();			
 			super.keyUpHandler(event); 			
 			 				
 		}	
	 

 		protected function mouseRollOverHandler(event:MouseEvent):void{
    		listFocuceFg = true;
    		//dropDownList.setFocus();    		
    	}
    	
    	protected function mouseRollOutHandler(event:MouseEvent):void{
    		listFocuceFg = false;
    	}
    	
    	// 리스트 클릭시에
	 	protected function listItemClick(event:ListEvent):void{	 	
 	 		_selectedItem = event.target.selectedItem;
	 		//_selectedIdx  = event.target.selectedItem.ORG_IDX;			 		
	 		selectItemTextView(event.target.selectedItem);
	 		
	 		dispatchEvent(new ListEvent(ListEvent.ITEM_CLICK));		  			 			 		
	 	}
	 
	/*************************************************************************************
	 * List DropDown/Up   
	 * *********************************************************************************/
		public function stageMouseDownHandler(event:MouseEvent):void{
			if(! listFocuceFg){
				closeDropDown();	
			}												
			removeEventListener(MouseEvent.MOUSE_DOWN,stageMouseDownHandler);
		}
			 	
	 	public var point:Point;
	 	
	 	// 키 업 되었을때  불려지는 함수 . 	 	
		protected function openDropDown():void{
			
			if(! dropDownEnabled) return;
			
			point = new Point(0,0);
			var searchResult:ArrayCollection;
			var resultLenght:int;
			

			
			//////////////////////////////////////////////////////////////////////// 
			// 입력 받은 글자로 DB search..그리고 arrayCollection에 담음 .
			if(keyStr == "") {
				parentApplication.contactListCollection = null;
				return;
			} 
			parentApplication.getKeySearch(keyStr);
			//searchResult = new ArrayCollection(hac.rtnAutoCompleteList(keyStr,labelField,copyDataProvider));
						
			//resultLenght = parentApplication.contactCollection.length;	

							
			point = localToGlobal(point);			
			
			if(dropDownAlign == "center"){ // 중앙에 위치
				dropDownList.x = (point.x + (width /2)) - (dropDownWidth/2);	
			}else if(dropDownAlign == "right"){// 오른쪽 기준으로
				dropDownList.x = (point.x + width) - dropDownWidth ;
			}else { // 기본 왼쪽 기준으로
				dropDownList.x = point.x ;
			}								 
			dropDownList.y = point.y + (height + 1);	
			_selectedIdx = -1;
		}
		
		public function setDataDropDown(ac:ArrayCollection):void {
			dropDownList.dataProvider = parentApplication.contactCollection;				
			if(! dropDownOpenFg){					
				PopUpManager.addPopUp(dropDownList,this);			
				dropDownOpenFg = true;
				stage.addEventListener(MouseEvent.MOUSE_DOWN,stageMouseDownHandler);					
			}	
			
								
			if(dropDownList.dataProvider.length == 0){
				dropDownOpenFg = true;
				closeDropDown();
				return;			
			}	
		}		

		public function closeDropDown():void{			
			if(dropDownOpenFg){
				dropDownList.dataProvider = copyDataProvider;	
				PopUpManager.removePopUp(dropDownList);
				dropDownOpenFg = false;		
			}
		}
								
		
	/*************************************************************************************
	 * etc   
	 * *********************************************************************************/			
		
		protected function selectItemTextView(itemData:Object):void{
			
			if(itemData.hasOwnProperty(labelField)){
				text = itemData[labelField];	
			}			
			closeDropDown();
		}
				

		
		
	}//class CompTextInput


} //package
	
	
	
	
/*================================================================================================
/									
/										자동 완성 처리 Classs
/
/	
===================================================================================================*/
	
	import mx.collections.ArrayCollection;
	import mx.utils.ObjectUtil;
	import mx.utils.StringUtil;
	import mx.controls.Alert;
	
	//자동 완성 로직 Classs	
	class HangulAutoComplete{
	
		// 초성, 중성, 종성에 대한 코드 테이블.
		private const choSungTbl:String 		= "ㄱㄲㄴㄷㄸㄹㅁㅂㅃㅅㅆㅇㅈㅉㅊㅋㅌㅍㅎ";
		private const jungSungTbl:String 		= "ㅏㅐㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜㅝㅞㅟㅠㅡㅢㅣ";
		private const jongSungTbl:String 		= " ㄱㄲㄳㄴㄵㄶㄷㄹㄺㄻㄼㄽㄾㄿㅀㅁㅂㅄㅅㅆㅇㅈㅊㅋㅌㅍㅎ"; //앞에 공백 주의 종성이 없는 문자 위해서.
		private const uniCodeHangulBase:uint 	= 0xAC00;
		private const uniCodeHangulLast:uint 	= 0xD79F;
		
		
	/*************************************************************************************
	 * 검색 결과 리턴 / 자소결합 함수 / 자소 분리 함수
	 * *********************************************************************************/
		 		
		//주어진 문자로 검색
		public function rtnAutoCompleteList(keyStr:String,labelStr:String,dataList:ArrayCollection):Array{
			var returnValue:Array =	[];		
			var dataListLength:int;			//비교대상 데이터 리스트 길이 값  지정변수 
			var keyStrLength:int;			//입력값 길이
			var keyStrCodeArray:Array;		//입력값의 발라낸 코드 배열 값 
			var compareStr:String ;			//비교 대상 데이터 값 저장 변수
			var compareStrCodeArray:Array;	//비교 대상 데이터의 발라낸 코드 배열 값 
			var pattern:RegExp = new RegExp(" ","g"); //공백 제거 패턴..
			var addPushFg:Boolean; 			//넣을지 말지 Flag 변수
											
			keyStr = mx.utils.StringUtil.trim(keyStr);			
							
			if(! dataList || keyStr == "") return returnValue;

			//발라 내서 찾자..
			keyStrCodeArray = divideJaso(keyStr);						
			dataListLength 	= dataList.length;
			keyStrLength	= keyStr.length;
					
			
			for(var i:int = 0 ; i < dataListLength ; i++){
				addPushFg = false;
				compareStr = mx.utils.StringUtil.trim(dataList[i][labelStr]);	
				compareStr = compareStr.replace(pattern, "");					
				compareStr = compareStr.substr(0,keyStrLength);											
				
				if(compareStr.length < keyStrLength) continue; //입력값 3자 인데 데이터가 2자 라면 다음으로 .
				
				compareStrCodeArray = divideJaso(compareStr);						
				addPushFg =  rtnCompareResult(keyStrCodeArray,compareStrCodeArray); // 비교결과
																					
				if(addPushFg){
					dataList[i].ORG_IDX = i; // 원본 데이터의 인덱스 										
					returnValue.push(dataList[i]);											
				}														
								
			}//for i
			
			returnValue.sortOn(labelStr);
			
			
			return returnValue;
		}
	
	
	
		//자소 분리 초성 중성 종성 으로 발라 내는 함수.
		public function divideJaso(value:String):Array{
			var returnValue:Array = [];
	      	var choSungCode:int,jungSungCode:int,jongSungCode:int;	      	
			var choSungStr:String,jungSungStr:String,jongSungStr:String;
			var hangulFg:Boolean;
			var strCode:Number;            
			var nUniCode:int;
			var valueLength:int = value.length;
			
			
			for(var i:int = 0 ; i < valueLength ; i++){
				choSungStr	="";
				jungSungStr	="";
				jongSungStr	="";
				hangulFg = false;
				
				strCode = value.substr(i,1).charCodeAt();	
															
				//[한글인지 아닌지 여부  , 문자코드 , 초성 문자,중성문자,종성문자] 완성되지 않는 글자도 포함..
				if((strCode < uniCodeHangulBase) || (strCode > uniCodeHangulLast)){	 
					if(choSungTbl.indexOf(value.substr(i,1)) > -1){ //초성인가?
						hangulFg 	= true;
						choSungStr 	= value.substr(i,1);						
					}else if(jungSungTbl.indexOf(value.substr(i,1)) > -1){ //중성인가?
						hangulFg 	= true;
						jungSungStr = value.substr(i,1);						
					}else if(mx.utils.StringUtil.trim(jongSungTbl).indexOf(value.substr(i,1)) > -1){ //종성인가?
						hangulFg = true;
						jongSungStr = value.substr(i,1);						
					}
			
	    		}else{
	    			hangulFg = true;
	   				nUniCode 		= strCode - uniCodeHangulBase;
					choSungCode 	= nUniCode / (21 * 28);
					choSungStr  	= choSungTbl.charAt(choSungCode);
					
					nUniCode 		= nUniCode % (21 * 28);
					jungSungCode 	= nUniCode / 28;
					jungSungStr 	=  jungSungTbl.charAt(jungSungCode);
					
					nUniCode 		= nUniCode % 28;
					jongSungCode 	= nUniCode;
	   				jongSungStr 	= jongSungTbl.charAt(jongSungCode);
	   				jongSungStr		= mx.utils.StringUtil.trim(jongSungStr); // " " 일경우 ""으로 
	    		} // if

				returnValue.push({ HANGUL_FG 	: 	hangulFg 
    							,  STR_CODE  	:	strCode
    							,  CHOSUNG_STR 	:	choSungStr
    							,  JUNGSUNG_STR :	jungSungStr
    							,  JONGSUNG_STR :	jongSungStr
    							,  FULL_STR : choSungStr+jungSungStr+jongSungStr
    							});	    
	    								    		  				
			}// for i
							
             				
			return returnValue;
		}

		
		//////////////////////////////////////////
		/////      내가 쓰는 함수  ..        ////////
		//자소 분리 초성 중성 종성 으로 발라 내는 함수.
		public function divideJaso_FullRtn(value:String):String{
								
			
			var returnValue:Array = [];
	      	var choSungCode:int,jungSungCode:int,jongSungCode:int;	      	
			var choSungStr:String,jungSungStr:String,jongSungStr:String, engStr:String;
			var hangulFg:Boolean;
			var strCode:Number;            
			var nUniCode:int;
			var valueLength:int = value.length;
			var rtnFullStr:String="";
			
			for(var i:int = 0 ; i < valueLength ; i++){
				choSungStr	="";
				jungSungStr	="";
				jongSungStr	="";
				engStr="";
				hangulFg = false;
				
				strCode = value.substr(i,1).charCodeAt();	
															
				//[한글인지 아닌지 여부  , 문자코드 , 초성 문자,중성문자,종성문자] 완성되지 않는 글자도 포함..
				if((strCode < uniCodeHangulBase) || (strCode > uniCodeHangulLast)){	 
					if(choSungTbl.indexOf(value.substr(i,1)) > -1){ //초성인가?
						hangulFg 	= true;
						choSungStr 	= value.substr(i,1);						
					}else if(jungSungTbl.indexOf(value.substr(i,1)) > -1){ //중성인가?
						hangulFg 	= true;
						jungSungStr = value.substr(i,1);						
					}else if(mx.utils.StringUtil.trim(jongSungTbl).indexOf(value.substr(i,1)) > -1){ //종성인가?
						hangulFg = true;
						jongSungStr = value.substr(i,1);						
					}else {
						engStr = value.substr(i,1);		
					}
			
	    		}else{
	    			hangulFg = true;
	   				nUniCode 		= strCode - uniCodeHangulBase;
					choSungCode 	= nUniCode / (21 * 28);
					choSungStr  	= choSungTbl.charAt(choSungCode);
					
					nUniCode 		= nUniCode % (21 * 28);
					jungSungCode 	= nUniCode / 28;
					jungSungStr 	=  jungSungTbl.charAt(jungSungCode);
					
					nUniCode 		= nUniCode % 28;
					jongSungCode 	= nUniCode;
	   				jongSungStr 	= jongSungTbl.charAt(jongSungCode);
	   				jongSungStr		= mx.utils.StringUtil.trim(jongSungStr); // " " 일경우 ""으로 
	    		} // if

/* 				returnValue.push({ HANGUL_FG 	: 	hangulFg 
    							,  STR_CODE  	:	strCode
    							,  CHOSUNG_STR 	:	choSungStr
    							,  JUNGSUNG_STR :	jungSungStr
    							,  JONGSUNG_STR :	jongSungStr
    							,  FULL_STR : choSungStr+jungSungStr+jongSungStr
    							});	     */
    							
    			rtnFullStr = rtnFullStr + choSungStr+jungSungStr+jongSungStr+engStr;
    			if(rtnFullStr==""){
    				return value;
    			} 				
	    								    		  				
			}// for i
							
             				
			return rtnFullStr;
		}

















		//비교 결과 리턴
		//이부분에서 비교 허용 범위를 조정 하시기 바랍니다.		
		public function rtnCompareResult(keyStrArray:Array,compareStrArray:Array):Boolean{
			var equalCount:int		= 0;
			var keyStrLength:int 	= keyStrArray.length;			
			
							
			for(var i:int = 0 ; i < keyStrLength ; i++){
			
				if(i < (keyStrLength-1)){ // 마지막 글자가 아닌  이전 비교 글자는 반드시 같아야 함 					
					if(keyStrArray[i].STR_CODE == compareStrArray[i].STR_CODE){
						equalCount ++;
						
					}	
				}else{ // 마지막 글자는  종성 부분 비교 제외 
					if(keyStrArray[i].STR_CODE == compareStrArray[i].STR_CODE){
						equalCount ++;
					}else{ 						
						if(keyStrArray[i].HANGUL_FG){ //한글일 경우														
							//입력 글자가 초성만 있을경우
							if(keyStrArray[i].CHOSUNG_STR != "" && keyStrArray[i].JUNGSUNG_STR == "" && keyStrArray[i].JONGSUNG_STR == ""){								
								if(keyStrArray[i].CHOSUNG_STR == compareStrArray[i].CHOSUNG_STR){
									equalCount ++;
								}									
							}else if(keyStrArray[i].CHOSUNG_STR != "" && keyStrArray[i].JUNGSUNG_STR != "" && keyStrArray[i].JONGSUNG_STR == ""){
								//입력 글자가 초성 중성만 있을 경우
								
								if(keyStrArray[i].CHOSUNG_STR == compareStrArray[i].CHOSUNG_STR && keyStrArray[i].JUNGSUNG_STR == compareStrArray[i].JUNGSUNG_STR ){
									equalCount ++;
								}
							}else if(keyStrArray[i].CHOSUNG_STR == "" && keyStrArray[i].JUNGSUNG_STR != "" && keyStrArray[i].JONGSUNG_STR == ""){
								//중성만 있을 경우 
								if(keyStrArray[i].JUNGSUNG_STR == compareStrArray[i].JUNGSUNG_STR){
									equalCount ++;  //허용 하지 않을려면 비교부분을 제거 하세요.
								}																									
							}else if(keyStrArray[i].CHOSUNG_STR == "" && keyStrArray[i].JUNGSUNG_STR != "" && keyStrArray[i].JONGSUNG_STR!= ""){
								//초 중 종성 다 있는 경우.								
								if(keyStrArray[i].STR_CODE == compareStrArray[i].STR_CODE){
									equalCount ++;
								}
							}				 
						}else{ //한글이 아니라면 ..
							if(keyStrArray[i].STR_CODE == compareStrArray[i].STR_CODE){
								equalCount ++;
							}	
						}
					}						
						
				}  		
					
			}//for i
			
			if(keyStrLength == equalCount){
				return true;	
			}else{
				return false;
			}
						
			
		}
								
		//자소 결합 -- 쓸일 없다.  -,.-; mergeJaso('ㅂ',ㅔ','ㄺ') => 뷁
		public function mergeJaso(choSung:String,jungSung:String,jongSung:String):String{
			var choSungPos:int , jungSungPos:int , jongSungPos:int , nUniCode:int;
								
	    	choSungPos  = choSungTbl.indexOf(choSung);     // 초성 위치
	    	jungSungPos = jungSungTbl.indexOf(jungSung);   // 중성 위치
			jongSungPos = jongSungTbl.indexOf(jongSung);   // 종성 위치

	 	    //계산식
	    	nUniCode =uniCodeHangulBase + (choSungPos * 21 + jungSungPos)* 28 + jongSungPos;	    		    
	    	
		    // 코드값을 문자로 변환			
	 	   	return String.fromCharCode(nUniCode);
	
		}
		
	
	}//class	